﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace SQL_Manager.OTServ
{
    //TODO: Extend Players class
    //TODO: Function to list all players (required for player lookup form)
    //TODO: Decide whether we need Position and Outfit
    public enum Sex_t
    {
        Female = 0,
        Male = 1
    }

    public enum Direction_t
    {
        North = 0,
        West = 1,
        South = 3,
        East = 4
    }

    public struct Position
    {
        public int x;
        public int y;
        public int z;
        public bool init;
    }

    public struct Outfit
    {
        public int head;
        public int body;
        public int legs;
        public int feet;
        public int type;
        public int addons;
        public bool init;
    }

    sealed public class Player
    {
        private Hashtable _Data;
        private Database Db;

        private OTServ.Group _group;
        private OTServ.Outfit _outfit = new Outfit { init = false };
        private OTServ.Account _account;
        private OTServ.Position _position = new Position { init = false };

        #region Constructors

        //
        // Constructor for a new player
        //
        public Player()
        {
            Database.GetInstance(out this.Db);
            this._Data = new Hashtable();
        }

        //
        // Constructor for a new player
        // - Assigns player by reference
        //
        public Player(out Player player)
        {
            Database.GetInstance(out this.Db);
            this._Data = new Hashtable();
            player = this;
        }

        //
        // Gets player by NAME
        //
        public Player(string Name)
        {
            Database.GetInstance(out this.Db);
            this.__retrieve(Name);
        }
        
        //
        // Gets player by NAME
        // - Assigns player by reference
        //
        public Player(string Name, out Player player)
        {
            Database.GetInstance(out this.Db);
            this.__retrieve(Name);
            player = this;
        }

        //
        // Gets player by ID
        //
        public Player(int Id)
        {
            Database.GetInstance(out this.Db);
            this.__retrieveId(Id);
        }

        //
        // Gets player by ID
        // - Assigns player by reference
        //
        public Player(int Id, out Player player)
        {
            Database.GetInstance(out this.Db);
            this.__retrieveId(Id);
            player = this;
        }

        #endregion

        #region Database-Related

        //
        // This saves every field, including custom ones.. since we did load them all
        // - This returns the # of rows affected; 0 is NO ROWS, which means it failed.
        //
        public int commit()
        {
            if (this._Data["id"] != null)
            {
                StringBuilder gstring = new StringBuilder("UPDATE players SET ");

                foreach (System.Collections.DictionaryEntry entry in this._Data)
                {
                    gstring.AppendFormat("{0}='{1}',", entry.Key, entry.Value);
                }

                gstring.Remove(gstring.Length - 1, 1);
                gstring.AppendFormat(" WHERE id = {0}", this._Data["id"]);

                return this.Db.execute(gstring.ToString());
            }
            else
            {
                StringBuilder fields = new StringBuilder("INSERT INTO players (");
                StringBuilder values = new StringBuilder(" VALUES(");

                foreach (System.Collections.DictionaryEntry entry in this._Data)
                {
                    fields.AppendFormat("{0},", entry.Key);
                    values.AppendFormat("'{0}',", entry.Value);
                }

                fields.Remove(fields.Length - 1, 1);
                values.Remove(values.Length - 1, 1);
                fields.AppendFormat(") {0})", values.ToString());

                return this.Db.execute(fields.ToString());
            }
        }

        //
        // This loads the player by NAME
        //
        private void __retrieve(string name)
        {
            this.Db.query(string.Format("SELECT * FROM players WHERE name = '{0}'", name), out this._Data);
            
            if (this._Data == null)
            {
                throw new Exceptions.PlayerNotFoundException();
            }
        }

        //
        // This loads the player by ID
        //
        private void __retrieveId(int Id)
        {
            this.Db.query(string.Format("SELECT * FROM players WHERE id = {0}", Id), out this._Data);

            if (this._Data == null)
            {
                throw new Exceptions.PlayerNotFoundException();
            }
        }

        #endregion

        #region Properties

        //
        // Properties
        //
        public int id
        {
            get
            {
                if (this._Data["id"] == null)
                {
                    return -1;
                }

                return Convert.ToInt32(this._Data["id"]);
            }
        }

        public string name
        {
            get
            {
                return (string)this._Data["name"];
            }
            set
            {
                this._Data["name"] = value;
            }
        }

        public uint account_id
        {
            get
            {
                return Convert.ToUInt32(this._Data["account_id"]);
            }
            set
            {
                this._Data["account_id"] = value;
            }
        }

        public Account account
        {
            get
            {
                if (this._account == null)
                {
                    new Account(this.account_id, out this._account);
                }
                return this._account;
            }
            set
            {
                this._account = value;
                this._Data["account_id"] = this._account.id;
            }
        }

        public int group_id
        {
            get
            {
                return Convert.ToInt32(this._Data["group_id"]);
            }
            set
            {
                this._Data["group_id"] = value;
            }
        }

        public Group group
        {
            get
            {
                if (this._group == null)
                {
                    new Group(this.group_id, out this._group);
                }
                return this._group;
            }
            set
            {
                this._group = value;
                this.group_id = value.id;
            }
        }

        public int sex
        {
            get
            {
                return Convert.ToInt32(this._Data["sex"]);
            }
            set
            {
                this._Data["sex"] = value;
            }
        }

        public int vocation
        {
            get
            {
                return Convert.ToInt32(this._Data["vocation"]);
            }
            set
            {
                this._Data["vocation"] = value;
            }
        }

        public int experience
        {
            get
            {
                return Convert.ToInt32(this._Data["experience"]);
            }
            set
            {
                this._Data["experience"] = value;
            }
        }

        public int level
        {
            get
            {
                return Convert.ToInt32(this._Data["level"]);
            }
            set
            {
                this._Data["level"] = value;
            }
        }

        public int maglevel
        {
            get
            {
                return Convert.ToInt32(this._Data["maglevel"]);
            }
            set
            {
                this._Data["maglevel"] = value;
            }
        }

        public int health
        {
            get
            {
                return Convert.ToInt32(this._Data["health"]);
            }
            set
            {
                this._Data["health"] = value;
            }
        }

        public int healthmax
        {
            get
            {
                return Convert.ToInt32(this._Data["healthmax"]);
            }
            set
            {
                this._Data["healthmax"] = value;
            }
        }

        public int mana
        {
            get
            {
                return Convert.ToInt32(this._Data["mana"]);
            }
            set
            {
                this._Data["mana"] = value;
            }
        }

        public int manamax
        {
            get
            {
                return Convert.ToInt32(this._Data["manamax"]);
            }
            set
            {
                this._Data["manamax"] = value;
            }
        }

        public int manaspent
        {
            get
            {
                return Convert.ToInt32(this._Data["manaspent"]);
            }
            set
            {
                this._Data["manaspent"] = value;
            }
        }

        public int soul
        {
            get
            {
                return Convert.ToInt32(this._Data["soul"]);
            }
            set
            {
                this._Data["soul"] = value;
            }
        }

        public Outfit outfit
        {
            get
            {
                if (this._outfit.init == false)
                {
                    this._outfit = new Outfit { head = this.lookhead, body = this.lookbody, legs = this.looklegs, feet = this.lookfeet, type = this.looktype, addons = this.lookaddons, init = true };
                }

                return this._outfit;
            }
            set
            {
                this.lookhead = value.head;
                this.lookbody = value.body;
                this.looklegs = value.legs;
                this.lookfeet = value.feet;
                this.looktype = value.type;
                this.lookaddons = value.addons;
            }
        }

        public int direction
        {
            get
            {
                return Convert.ToInt32(this._Data["direction"]);
            }
            set
            {
                this._Data["direction"] = value;
            }
        }

        public int lookbody
        {
            get
            {
                return Convert.ToInt32(this._Data["lookbody"]);
            }
            set
            {
                this._Data["lookbody"] = value;
            }
        }

        public int lookfeet
        {
            get
            {
                return Convert.ToInt32(this._Data["lookfeet"]);
            }
            set
            {
                this._Data["lookfeet"] = value;
            }
        }

        public int lookhead
        {
            get
            {
                return Convert.ToInt32(this._Data["lookhead"]);
            }
            set
            {
                this._Data["lookhead"] = value;
            }
        }

        public int looklegs
        {
            get
            {
                return Convert.ToInt32(this._Data["looklegs"]);
            }
            set
            {
                this._Data["looklegs"] = value;
            }
        }

        public int looktype
        {
            get
            {
                return Convert.ToInt32(this._Data["looktype"]);
            }
            set
            {
                this._Data["looktype"] = value;
            }
        }

        public int lookaddons
        {
            get
            {
                return Convert.ToInt32(this._Data["lookaddons"]);
            }
            set
            {
                this._Data["lookaddons"] = value;
            }
        }

        public Position position
        {
            get
            {
                if (this._position.init == false)
                {
                    this._position = new Position { x = this.posx, y = this.posy, z = this.posz, init = false };
                }

                return this._position;
            }
            set
            {
                this._position = value;
                this.posx = value.x;
                this.posy = value.y;
                this.posz = value.z;
            }
        }

        public int posx
        {
            get
            {
                return Convert.ToInt32(this._Data["posx"]);
            }
            set
            {
                this._Data["posx"] = value;
            }
        }

        public int posy
        {
            get
            {
                return Convert.ToInt32(this._Data["posy"]);
            }
            set
            {
                this._Data["posy"] = value;
            }
        }

        public int posz
        {
            get
            {
                return Convert.ToInt32(this._Data["posz"]);
            }
            set
            {
                this._Data["posz"] = value;
            }
        }

        public int cap
        {
            get
            {
                return Convert.ToInt32(this._Data["cap"]);
            }
            set
            {
                this._Data["cap"] = value;
            }
        }

        public uint lastlogin
        {
            get
            {
                return Convert.ToUInt32(this._Data["lastlogin"]);
            }
            set
            {
                this._Data["lastlogin"] = value;
            }
        }

        public uint lastlogout
        {
            get
            {
                return Convert.ToUInt32(this._Data["lastlogout"]);
            }
            set
            {
                this._Data["lastlogout"] = value;
            }
        }

        public uint lastip
        {
            get
            {
                return Convert.ToUInt32(this._Data["lastip"]);
            }
            set
            {
                this._Data["lastip"] = value;
            }
        }

        public int save
        {
            get
            {
                return Convert.ToInt32(this._Data["save"]);
            }
            set
            {
                this._Data["save"] = value;
            }
        }

        public byte[] conditions
        {
            get
            {
                return (byte[])this._Data["conditions"];
            }
            set
            {
                this._Data["conditions"] = value;
            }
        }

        public int skull_type
        {
            get
            {
                return Convert.ToInt32(this._Data["skull_type"]);
            }
            set
            {
                this._Data["skull_type"] = value;
            }
        }

        public uint skull_time
        {
            get
            {
                return Convert.ToUInt32(this._Data["skull_time"]);
            }
            set
            {
                this._Data["skull_time"] = value;
            }
        }

        public string guildnick
        {
            get
            {
                return (string)this._Data["guildnick"];
            }
            set
            {
                this._Data["guildnick"] = value;
            }
        }

        public int loss_experience
        {
            get
            {
                return Convert.ToInt32(this._Data["loss_experience"]);
            }
            set
            {
                this._Data["loss_experience"] = value;
            }
        }

        public int loss_mana
        {
            get
            {
                return Convert.ToInt32(this._Data["loss_mana"]);
            }
            set
            {
                this._Data["loss_mana"] = value;
            }
        }

        public int loss_skills
        {
            get
            {
                return Convert.ToInt32(this._Data["loss_skills"]);
            }
            set
            {
                this._Data["loss_skills"] = value;
            }
        }

        public int loss_items
        {
            get
            {
                return Convert.ToInt32(this._Data["loss_items"]);
            }
            set
            {
                this._Data["loss_items"] = value;
            }
        }

        public int loss_containers
        {
            get
            {
                return Convert.ToInt32(this._Data["loss_containers"]);
            }
            set
            {
                this._Data["loss_containers"] = value;
            }
        }

        public int rank_id
        {
            get
            {
                return Convert.ToInt32(this._Data["rank_id"]);
            }
            set
            {
                this._Data["rank_id"] = value;
            }
        }

        public int town_id
        {
            get
            {
                return Convert.ToInt32(this._Data["town_id"]);
            }
            set
            {
                this._Data["town_id"] = value;
            }
        }

        public int balance
        {
            get
            {
                return Convert.ToInt32(this._Data["balance"]);
            }
            set
            {
                this._Data["balance"] = value;
            }
        }

        public int stamina
        {
            get
            {
                return Convert.ToInt32(this._Data["stamina"]);
            }
            set
            {
                this._Data["stamina"] = value;
            }
        }

        public ushort online
        {
            get
            {
                return Convert.ToUInt16(this._Data["online"]);
            }
            set
            {
                this._Data["online"] = value;
            }
        }

        #endregion
    }
}
